import G6 from '@antv/g6'
import {
  pureColor,
  nodePadding,
  nodeFontSize,
  nodeBorderRadius,
  collapseGap,
  collapseRadius,
  riskIconWidth,
  riskIconHeight,
  riskIconUrl,
  riskIconGap,
  shadowColor,
  shadowBlur,
  shadowOffsetX,
  shadowOffsetY,
  investedBg,
  investedWidth,
  investedHeight,
} from './graphStyle'

export default function registerFn({ limitLen }) {
  // default-node
  G6.registerNode(
    'default-node',
    {
      addRiskIcon(cfg, group) {
        const iconUrl = cfg.riskStatus === 'exist' ? riskIconUrl.exist : riskIconUrl.none
        return group.addShape('image', {
          attrs: {
            width: riskIconWidth,
            height: riskIconHeight,
            img: iconUrl,
          },
        })
      },
      addLabel(cfg, group) {
        const color = cfg?.color ?? pureColor.regularText

        return group.addShape('text', {
          attrs: {
            text: cfg?.text?.replace(/(.{6})/g, '$1\n'),
            fontSize: nodeFontSize,
            textAlign: 'left',
            textBaseline: 'middle',
            fill: color,
          },
        })
      },
      addMarker(cfg, group) {
        return group.addShape('marker', {
          attrs: {
            r: collapseRadius,
            symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
            stroke: pureColor.blue,
            lineWidth: 1,
            fill: pureColor.white,
          },
          name: 'collapse-icon',
        })
      },
      draw(cfg, group) {
        // 是否有风险标记
        const hasRiskIcon = !!cfg?.riskStatus
        // 是否有子元素
        const hasChildren = cfg?.children?.length > 0

        const bgColor = cfg?.bgColor ?? pureColor.white

        const keyShape = group.addShape('rect', {
          attrs: {
            lineWidth: 1,
            fill: bgColor,
            radius: nodeBorderRadius,
            shadowColor,
            shadowBlur,
            shadowOffsetX,
            shadowOffsetY,
          },
        })

        const textShape = this.addLabel(cfg, group)

        // 主容器宽高
        const width =
          textShape.getBBox().width +
          (hasRiskIcon ? riskIconWidth + riskIconGap : 0) +
          nodePadding[1] * 2
        const height = textShape.getBBox().height + nodePadding[0] * 2

        // 主容器坐标
        const baseX = 0
        const baseY = -height / 2

        textShape.attr({
          x: baseX + (hasRiskIcon ? riskIconWidth + riskIconGap : 0) + nodePadding[1],
          y: 0,
        })
        keyShape.attr({
          x: baseX,
          y: baseY,
          width,
          height,
        })

        if (hasRiskIcon) {
          const riskIconShape = this.addRiskIcon(cfg, group)
          riskIconShape.attr({
            x: baseX + nodePadding[1],
            y: -riskIconHeight / 2,
          })
        }

        if (hasChildren) {
          // 添加marker
          const markerShape = this.addMarker(cfg, group)
          markerShape.attr({
            x: baseX + width + collapseGap + collapseRadius,
            y: baseY + height / 2,
          })
        }

        return keyShape
      },
      update(cfg, item) {
        const group = item.getContainer()
        const icon = group.find((e) => e.get('name') === 'collapse-icon')
        icon?.attr('symbol', cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse)
      },
    },
    'single-node'
  )
  // root-node
  G6.registerNode(
    'root-node',
    {
      options: {
        fontSize: 18,
        contentHeight: 40,
        logoWidth: 28,
        logoHeight: 28,
        logoUrl: '/健身房.png',
        logoGap: 6,
      },
      addLogo(cfg, group) {
        const { logoWidth, logoHeight, logoUrl } = this.options
        return group.addShape('image', {
          attrs: {
            width: logoWidth,
            height: logoHeight,
            img: cfg?.logoUrl || logoUrl,
          },
        })
      },
      addLabel(cfg, group) {
        const { fontSize } = this.options
        const limitLen = 10
        const text =
          cfg?.text?.length > limitLen
            ? cfg.text.replace(new RegExp(`(.{${limitLen}})`, 'g'), '$1\n')
            : cfg.text
        return group.addShape('text', {
          attrs: {
            text,
            fontSize,
            textAlign: 'left',
            textBaseline: 'middle',
            fill: pureColor.white,
          },
        })
      },
      addMarker(cfg, group) {
        return group.addShape('marker', {
          attrs: {
            r: collapseRadius,
            symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
            stroke: pureColor.blue,
            lineWidth: 1,
            fill: pureColor.white,
          },
          name: 'collapse-icon',
        })
      },
      draw(cfg, group) {
        const { contentHeight, logoWidth, logoHeight, logoGap } = this.options
        const hasChildren = cfg?.children?.length > 0

        const keyShape = group.addShape('rect', {
          attrs: {
            lineWidth: 1,
            fill: pureColor.blue,
            radius: nodeBorderRadius,
            shadowColor,
            shadowBlur,
            shadowOffsetX,
            shadowOffsetY,
          },
        })
        // 添加logo
        const logoShape = this.addLogo(cfg, group)
        // 添加文本
        const textShape = this.addLabel(cfg, group)

        // 主容器宽高
        const width = textShape.getBBox().width + nodePadding[1] * 2 + logoWidth + logoGap
        const height = contentHeight + nodePadding[0] * 2

        // 主容器坐标
        const baseX = -width
        const baseY = -height / 2

        // 定位
        logoShape.attr({
          x: baseX + nodePadding[1],
          y: -logoHeight / 2,
        })
        textShape.attr({
          x: baseX + nodePadding[1] + logoWidth + logoGap,
          y: 0,
        })
        keyShape.attr({
          x: baseX,
          y: baseY,
          width,
          height,
        })

        if (hasChildren) {
          // 添加marker
          const markerShape = this.addMarker(cfg, group)
          markerShape.attr({
            x: baseX + width + collapseGap + collapseRadius,
            y: baseY + height / 2,
          })
        }

        return keyShape
      },
      update(cfg, item) {
        const group = item.getContainer()
        const icon = group.find((e) => e.get('name') === 'collapse-icon')
        icon.attr('symbol', cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse)
      },
    },
    'single-node'
  )
  // risk-node
  G6.registerNode(
    'risk-node',
    {
      options: {
        lineGap: 6,
      },
      addRiskIcon(cfg, group) {
        const iconUrl = cfg.riskStatus === 'exist' ? riskIconUrl.exist : riskIconUrl.none
        return group.addShape('image', {
          attrs: {
            width: riskIconWidth,
            height: riskIconHeight,
            img: iconUrl,
          },
        })
      },
      addLabel(cfg, group) {
        const text =
          cfg?.text?.length > limitLen
            ? cfg.text.replace(new RegExp(`(.{${limitLen}})`, 'g'), '$1\n')
            : cfg.text

        const fontColor = cfg.color || pureColor.regularText
        return group.addShape('text', {
          attrs: {
            text,
            fontSize: nodeFontSize,
            textAlign: 'left',
            textBaseline: 'middle',
            fill: fontColor,
          },
        })
      },
      addNumber(cfg, group) {
        let fontColor = ''
        if (cfg.riskNumColor) fontColor = cfg.riskNumColor
        else if (cfg.riskStatus === 'exist') fontColor = pureColor.red
        else if (cfg.riskStatus === 'none') fontColor = pureColor.blue
        else fontColor = pureColor.blue

        return group.addShape('text', {
          attrs: {
            text: `${cfg.riskNum} 条`,
            fontSize: nodeFontSize,
            textAlign: 'left',
            textBaseline: 'middle',
            fill: fontColor,
            cursor: cfg?.linkable === false ? 'default' : 'pointer',
          },
          name: 'risk-num-label',
        })
      },
      addMarker(cfg, group) {
        return group.addShape('marker', {
          attrs: {
            r: collapseRadius,
            symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
            stroke: pureColor.blue,
            lineWidth: 1,
            fill: pureColor.white,
          },
          name: 'collapse-icon',
        })
      },
      draw(cfg, group) {
        const { lineGap } = this.options

        // 是否有风险标记
        const hasRiskIcon = !!cfg?.riskStatus
        // 是否有子元素
        const hasChildren = cfg?.children?.length > 0
        // 背景色
        const bgColor = cfg?.bgColor ?? pureColor.white

        const keyShape = group.addShape('rect', {
          attrs: {
            lineWidth: 1,
            fill: bgColor,
            radius: nodeBorderRadius,
            shadowColor,
            shadowBlur,
            shadowOffsetX,
            shadowOffsetY,
          },
          name: 'rect',
        })

        // 名称文本
        const labelShape = this.addLabel(cfg, group)
        const numShape = this.addNumber(cfg, group)

        const width =
          Math.max(labelShape.getBBox().width, numShape.getBBox().width) +
          (hasRiskIcon ? riskIconWidth + riskIconGap : 0) +
          nodePadding[1] * 2
        const height =
          labelShape.getBBox().height + numShape.getBBox().height + lineGap + nodePadding[0] * 2

        // 主容器坐标
        const baseX = 0
        const baseY = -height / 2

        labelShape.attr({
          x: baseX + nodePadding[1] + (hasRiskIcon ? riskIconWidth + riskIconGap : 0),
          y: baseY + nodePadding[0] + labelShape.getBBox().height / 2,
        })
        numShape.attr({
          x: baseX + nodePadding[1] + (hasRiskIcon ? riskIconWidth + riskIconGap : 0),
          y:
            baseY +
            nodePadding[0] +
            labelShape.getBBox().height +
            lineGap +
            numShape.getBBox().height / 2,
        })

        keyShape.attr({
          x: baseX,
          y: baseY,
          width,
          height,
        })

        if (hasRiskIcon) {
          const riskIconShape = this.addRiskIcon(cfg, group)
          riskIconShape.attr({
            x: baseX + nodePadding[1],
            y: -riskIconHeight / 2,
          })
        }
        if (hasChildren) {
          // 添加marker
          const markerShape = this.addMarker(cfg, group)
          markerShape.attr({
            x: baseX + width + collapseGap + collapseRadius,
            y: baseY + height / 2,
          })
        }

        return keyShape
      },
      update(cfg, item) {
        const group = item.getContainer()
        const icon = group.find((e) => {
          return e.get('name') === 'collapse-icon'
        })
        icon?.attr('symbol', cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse)
      },
    },
    'single-node'
  )
  // more-node
  G6.registerNode('more-node', {
    addWrapper(group) {
      return group.addShape('rect', {
        attrs: {
          lineWidth: 1,
          fill: pureColor.white,
          radius: nodeBorderRadius,
          shadowColor,
          shadowBlur,
          shadowOffsetX,
          shadowOffsetY,
        },
      })
    },
    addLabel(group) {
      return group.addShape('text', {
        attrs: {
          text: '显示全部',
          fontSize: nodeFontSize,
          textAlign: 'left',
          textBaseline: 'middle',
          fill: pureColor.blue,
          cursor: 'pointer',
        },
        name: 'more-label',
      })
    },
    draw(cfg, group) {
      const wrapperShape = this.addWrapper(group)
      const labelShape = this.addLabel(group)

      const width = labelShape.getBBox().width + nodePadding[1] * 2
      const height = labelShape.getBBox().height + nodePadding[0] * 2

      // 主容器坐标
      const baseX = 0
      const baseY = -height / 2

      wrapperShape.attr({
        width,
        height,
        x: baseX,
        y: baseY,
      })
      labelShape.attr({
        x: baseX + nodePadding[1],
        y: 0,
      })
      return wrapperShape
    },
  })

  G6.registerEdge(
    'default-edge',
    {
      afterDraw(cfg, group) {
        const model = cfg.targetNode.getModel()
        if (!model.invested) return

        const shape = group.get('children')[0]
        const midPoint = shape.getPoint(0.5)

        group.addShape('rect', {
          attrs: {
            width: investedWidth,
            height: investedHeight,
            fill: investedBg,
            radius: 2,
            x: midPoint.x - investedWidth / 2,
            y: midPoint.y - investedHeight / 2,
          },
        })
        group.addShape('text', {
          attrs: {
            text: model.invested,
            fontSize: 14,
            textAlign: 'center',
            textBaseline: 'middle',
            fill: '#fff',
            x: midPoint.x,
            y: midPoint.y + 1,
          },
        })
      },
      update: undefined,
    },
    'cubic-horizontal'
  )
}
